package dnbW.dbW.sucxentdbW;

import dnbW.dbW.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * This class is in charge of managing all leaf paths in a SUCXENT++ data source
 * @author truongbaquan
 */
public class LeafPathManager {
    private DataSource dataSource;

    // <editor-fold defaultstate="collapsed" desc="Paths">
    private LeafPath[] leafPaths;

    /**
     * Checks whether the list of paths is initialized or not
     * @return
     */
    public boolean isPathsInitialized() {
        return (this.leafPaths != null);
    }

    /**
     * Gets a path with the given pathId of the current data source
     * @param pathId    Path Id (one-based)
     * @return          The path with the given pathId
     */
    public LeafPath getPath(int pathId) {
        return this.leafPaths[pathId-1];
    }

    public LeafPath[] getPaths() {
        return this.leafPaths;
    }

    public int getNumberOfPaths() {
        return this.leafPaths.length;
    }

    private Map<String, LeafPath> leafPathExpMap = new HashMap<String, LeafPath>();

    public LeafPath getPath(String sqlPathExp) {
        return this.leafPathExpMap.get(sqlPathExp);
    }

    public boolean isLeafPath(String sqlPathExp) {
        return this.leafPathExpMap.containsKey(sqlPathExp);
    }
    // </editor-fold>

    public LeafPathManager(DataSource dataSource) {
        this.dataSource = dataSource;
        this.loadLeafPaths();
    }

    /**
     * Finds all leaf paths in the data source from the database and returns the newly added paths
     * @return  Newly added paths (the paths that do not exist in the memory before loading)
     */
    public List<LeafPath> loadLeafPaths() {
        try {
            ResultSet results;
            Statement statement = this.dataSource.getDatabase().getDbConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
            statement.executeUpdate("USE [" + this.dataSource.getDatabase().getDbName() + "];");

            // get number of paths
            results = statement.executeQuery("select Max(PathId) from " + this.dataSource.getName() + "_Path");
            int maxPathId = 0;
            if (results.next()) {
                maxPathId = results.getInt(1);
            }
            if (maxPathId == 0) return null;

            this.leafPaths = new LeafPath[maxPathId];
            int pathId;
            String pathExp;
            LeafPath leafPath;
            ArrayList<LeafPath> addedPaths = new ArrayList<LeafPath>();
            results = statement.executeQuery("select * from " + this.dataSource.getName() + "_Path");
            while (results.next()) {
                pathId = results.getInt("PathId");
                pathExp = results.getString("PathExp");
                leafPath = LeafPath.buildPathFromSqlPathExp(dataSource, pathExp, pathId);
                this.leafPaths[pathId-1] = leafPath;
                this.leafPathExpMap.put(pathExp, leafPath);
                addedPaths.add(leafPath);
            }
            results.close();
            statement.close();
            return addedPaths;
        }
        catch (SQLException ex) {
            System.err.println(ex.getMessage());
            return new ArrayList<LeafPath>();
        }
    }

    public boolean isLeafPathNullValue(LeafPath leafPath) {
        try {
            Statement statement = this.dataSource.getDatabase().getDbConnection().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
            statement.executeUpdate("USE [" + this.dataSource.getDatabase().getDbName() + "];");

            String sql;
            if (leafPath.isAttribute()) {
                sql = "select top 1 * from " + this.dataSource.getName() + "_Attribute " +
                        "where PathId = " + leafPath.getPathId() + " and LeafValue is not null";
            }
            else {
                sql = "select top 1 * from " + this.dataSource.getName() + "_PathValue " +
                        "where PathId = " + leafPath.getPathId() + " and LeafValue is not null";
            }
            ResultSet sqlResult = statement.executeQuery(sql);
            boolean isNull = !(sqlResult.next());
            statement.close();
            return isNull;
        } catch (SQLException ex) {
            System.err.println(ex.getMessage());
            ex.printStackTrace();
            return false;
        }
    }
}
